package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * AutoFillAspect 实体类
 *
 * @author Xiaolaodi
 * @description
 * @create 2025/5/17
 */
/*
*  实现公共字段自动填充处理：自定义注解+定义切面类+在切面方法中用反射注入
*  自定义切面，专门处理切入点的方法->这里是打了 @AutoFill 注解且在mapper包下的方法。
* */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
	/*
	*  切入点,针对mapper里方法进行拦截，注意粒度大小
	*  既满足mapper方法有需要注解
	* */
	@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
	public void AutoFillPointCut() {}
	/*
	* 切面方法
	* */
	@Before("AutoFillPointCut()")
	public void autoFill(JoinPoint joinPoint) {
		log.info("开始进行公共字段的填充...");
		//1.获取当前被拦截方法上的数据库操作类型
		org.aspectj.lang.reflect.MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //方法签名对象
		AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得数据库操作类型
		OperationType operationType = autoFill.value();
		//2.获取到当前被拦截的方法的参数--实体对象.放在参数的第一位
		Object[] args = joinPoint.getArgs();
		if(args == null && args.length == 0) {
			return;
		}
		Object entity = args[0];
		//3.准备赋值数据
		LocalDateTime localDateTime = LocalDateTime.now();
		Long currentId = BaseContext.getCurrentId();
		//4.根据当前操作类型，用反射为其赋值。
		if(operationType == OperationType.INSERT) {
			//为四个公共字段赋值
			try{
				Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
				Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);
				Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
				Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);

				//通过反射为对象赋值
				setCreateTime.invoke(entity, localDateTime);
				setCreateUser.invoke(entity, currentId);
				setUpdateTime.invoke(entity, localDateTime);
				setUpdateUser.invoke(entity, currentId);
			}catch (Exception e){
				e.printStackTrace();
			}
		}else  {
			//为两个公共字段赋值
			try{
				Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
				Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);

				//通过反射为对象赋值
				setUpdateTime.invoke(entity, localDateTime);
				setUpdateUser.invoke(entity, currentId);
			}catch (Exception e){
				e.printStackTrace();
			}
		}
	}
}
